// Copyright (C) 2023 即时通讯网(52im.net) & Jack Jiang.
// The RainbowChat Project. All rights reserved.
// 
// 【本产品为著作权产品，合法授权后请放心使用，禁止外传！】
// 【本次授权给：<北京小羊驼科技有限公司>，授权编号：<NT231212144350>，代码指纹：<A.702363430.550>，技术对接人微信：<ID: wxid_wbyootvkdcgj22>】
// 【授权寄送：<收件：苏先生、地址：北京市大兴区北京密码西区6号楼1单元301、电话：18613885610、邮箱：bd@huiyuanxiang-inc.com>】
// 
// 【本系列产品在国家版权局的著作权登记信息如下】：
// 1）国家版权局登记名(简称)和权证号：RainbowChat    （证书号：软著登字第1220494号、登记号：2016SR041877）
// 2）国家版权局登记名(简称)和权证号：RainbowChat-Web（证书号：软著登字第3743440号、登记号：2019SR0322683）
// 3）国家版权局登记名(简称)和权证号：RainbowAV      （证书号：软著登字第2262004号、登记号：2017SR676720）
// 4）国家版权局登记名(简称)和权证号：MobileIMSDK-Web（证书号：软著登字第2262073号、登记号：2017SR676789）
// 5）国家版权局登记名(简称)和权证号：MobileIMSDK    （证书号：软著登字第1220581号、登记号：2016SR041964）
// * 著作权所有人：江顺/苏州网际时代信息科技有限公司
// 
// 【违法或违规使用投诉和举报方式】：
// 联系邮件：jack.jiang@52im.net
// 联系微信：hellojackjiang
// 联系QQ号：413980957
// 授权说明：http://www.52im.net/thread-1115-1-1.html
// 官方社区：http://www.52im.net
package com.x52im.rbchat.logic.chat_root;

import android.util.Log;

import java.lang.reflect.Field;
import java.util.HashMap;

import com.x52im.rainbowchat.im.dto.MsgType;

/**
 * 本类用于实现自动根据 {@link MsgType} 中定义的聊天消息常量个数，
 * 自动计算ListView中的ListAdaper要用到的 getItemViewType(int)、getViewTypeCount()
 * 两个方法的结果。
 * <p>
 * 如果没有本类，因“我”发出的、“我”收到的同一类聊天消息（比如文本消息），在UI屏现上是由
 * 两个不同的layout实现，那么就得像RainbowChat v6.0版之前那样，Android端同一类消息，比如
 * 文本消息就得定义两个UI显示类型：MsgType.toText、MsgType.comText这样的枚举形式，会导致
 * 跟MsgType中的常量定义不一致，而需要额外维护，就会增大开发者新增聊天消息类型时理解的复杂
 * 性和维护的难度。
 * <br>
 * 总之，本类的目的就是为了简化 AbstractChattingListAdapter.getItemViewType(int)
 * 、AbstractChattingListAdapter.getViewTypeCount()的维护，从而让开发者新增消息类型完整
 * 逻辑时少一些工作量。不然刚手上很容易蒙逼。
 *
 * @author Jack Jiang
 * @see AbstractChattingListAdapter
 * @see AbstractChattingListAdapter#getItemViewType(int)
 * @see AbstractChattingListAdapter#getViewTypeCount()
 * @since 6.0
 */
public class ChattingListItemTypeManager {
    private final static String TAG = ChattingListItemTypeManager.class.getSimpleName();
    private static ChattingListItemTypeManager instance = null;

    private HashMap<Integer, Integer> fildsIndexForValue = new HashMap<Integer, Integer>();

    public static ChattingListItemTypeManager getInstance() {
        if (instance == null)
            instance = new ChattingListItemTypeManager();
        return instance;
    }

    public ChattingListItemTypeManager() {
        try {
            // MsgType类信息
            Class msgTypeClazz = MsgType.class;
            // 实例化一下MsgType子类
            MsgTypeClass msgTypeObj = new MsgTypeClass();

            // 获得MsgType类中定义的所有消息类型（注意：getDeclaredFields可以
            // 取出public、private和proteced，但是不包括父类的申明字段）
            Field[] allFilds = msgTypeClazz.getDeclaredFields();

            // 将MsgType中的消息类型组织成一个hashmap，key=消息类型值、value=消息类型常量处于数组中的索引值
            for (int i = 0; i < allFilds.length; i++) {
                Field f = allFilds[i];
                fildsIndexForValue.put(f.getInt(msgTypeObj), i);
                Log.i(TAG, "【聊天列表type管理器】>>>> 聊天消息类型常量名=" + f.getName() + ", 常量值=" + f.getInt(msgTypeObj) + ", 索引值=" + i);
            }
        } catch (Exception e) {
            Log.e(TAG, "【聊天列表type管理器】【致命错误！】在自动计算聊天列表itemType" +
                    "和itemCount过程中发生错误，请检查您的 com.x52im.rainbowchat.im.dto.MsgType 接口中定义的常量值！", e);
        }
    }

    /**
     * 取出消息类型对应的ListView的type值（原则上该值为 >0 但小于ListAdapter的getViewTypeCount()返回结果）。
     * <p>
     * 本方法计算ItemViewType的逻辑，就是利用定义的消息类型常量位于MsgType接口中，所有常量这个数组的索引值，
     * 为了能同时实现支持isOutgoing=true这种情况，当isOutgoing=true时，ItemViewType值为false时的索引值+数组长度，
     * 从而解决了MsgType常量个数与ListView中的总ui个数不相符的问题。
     * <p>
     * 该值用于ListView的item在ui显示时进行复用，详见{@link AbstractChattingListAdapter#getItemViewType(int)}
     * 方法的API文档。
     *
     * @param msgType    聊天消息类型
     * @param isOutgoing true表示是“我”发出的消息，否则是收到的消息
     * @return
     */
    public int getItemViewType(int msgType, boolean isOutgoing) {
        try {
            if (!isOutgoing)
                return fildsIndexForValue.get(msgType);
            else
                return fildsIndexForValue.get(msgType) + fildsIndexForValue.size();
        } catch (Exception e) {
            Log.e(TAG, "【聊天列表type管理器】【致命错误！】getItemViewType()时发生错误，请检查您的 com.x52im.rainbowchat.im.dto.MsgType 接口中定义的常量值！", e);
            return 0;
        }
    }

    /**
     * ListView中复用的不同item的UI个数。详见{@link AbstractChattingListAdapter#getViewTypeCount()}
     * 方法的API文档。
     *
     * @return
     */
    public int getViewTypeCount() {
        return fildsIndexForValue.size() * 2;
    }

    // 因MsgType是接口，本类在反射时无法实例化它，所以通过本类来实现可实例化。
    public class MsgTypeClass implements MsgType {
        // do nothing
    }

//	public static void main(String[] args) throws Exception
//	{
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_TEXT, false));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_IMAGE, false));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_VOICE, false));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_GIFT$SEND, false));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_GIFT$GET, false));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_FILE, false));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_SHORTVIDEO, false));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_CONTACT, false));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_LOCATION, false));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_SYSTEAM$INFO, false));
//
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_TEXT, true));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_IMAGE, true));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_VOICE, true));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_GIFT$SEND, true));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_GIFT$GET, true));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_FILE, true));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_SHORTVIDEO, true));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_CONTACT, true));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_LOCATION, true));
//		System.out.println(ChattingListItemTypeManager.getInstance().getItemViewType(MsgType.TYPE_SYSTEAM$INFO, true));
//
//		System.out.println("getViewTypeCount="+ChattingListItemTypeManager.getInstance().getViewTypeCount());
//	}
}
